home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / usenet / volume11 / larn / part05 < prev    next >
Encoding:
Internet Message Format  |  1991-01-03  |  53.5 KB

  1. Path: uunet!zephyr.ens.tek.com!tekred!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v11i088:  larn - dungeon type adventure game, Part05/11
  5. Message-ID: <6719@tekred.CNA.TEK.COM>
  6. Date: 18 Dec 90 18:33:41 GMT
  7. Sender: news@tekred.CNA.TEK.COM
  8. Lines: 1682
  9. Approved: billr@saab.CNA.TEK.COM
  10.  
  11. Submitted-by: routley@tle.ENET.DEC.COM (Kevin Routley)
  12. Posting-number: Volume 11, Issue 88
  13. Archive-name: larn/Part05
  14. Environment: Unix, VMS, MS-DOS, termcap
  15.  
  16.  
  17.  
  18. #! /bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 5 (of 11)."
  25. # Contents:  Makefile movem.c savelev.c spells.c
  26. # Wrapped by billr@saab on Tue Dec 18 10:14:18 1990
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'Makefile'\"
  30. else
  31. echo shar: Extracting \"'Makefile'\" \(402 characters\)
  32. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  33. X#
  34. XOBJ=    action.o bill.o config.o create.o data.o diag.o display.o \
  35. X    fortune.o global.o help.o io.o main.o monster.o \
  36. X    moreobj.o movem.o msdos.o nap.o object.o regen.o savelev.o \
  37. X    scores.o signal.o spells.o spheres.o store.o \
  38. X    tok.o vms.o
  39. X#
  40. X#
  41. X
  42. XCFLAGS=-DDGK -DBSD -D'LARNHOME="/usr/users/routley/larncc/"'
  43. X
  44. Xlarn122: $(OBJ)
  45. X    cc -o larn122 $(OBJ) -ltermcap
  46. X
  47. X.c.o: 
  48. X    cc $(CFLAGS) -c $*.c 
  49. X
  50. X.c: header.h
  51. X
  52. END_OF_FILE
  53. if test 402 -ne `wc -c <'Makefile'`; then
  54.     echo shar: \"'Makefile'\" unpacked with wrong size!
  55. fi
  56. # end of 'Makefile'
  57. fi
  58. if test -f 'movem.c' -a "${1}" != "-c" ; then 
  59.   echo shar: Will not clobber existing file \"'movem.c'\"
  60. else
  61. echo shar: Extracting \"'movem.c'\" \(18818 characters\)
  62. sed "s/^X//" >'movem.c' <<'END_OF_FILE'
  63. X/*
  64. X *  movem.c (move monster)      Larn is copyrighted 1986 by Noah Morgan.
  65. X *
  66. X *  Here are the functions in this file:
  67. X *
  68. X *  movemonst()     Routine to move the monsters toward the player
  69. X *  build_proximity_ripple()  Build proximity ripple for smart monster move
  70. X *  move_scared()   Move scared monsters
  71. X *  move_smart()    Move smart monsters
  72. X *  move_dumb()     Move dumb monsters
  73. X *  mmove(x,y,xd,yd)    Function to actually perform the monster movement
  74. X */
  75. X#include "header.h"
  76. X#define min(x,y) (((x)>(y))?(y):(x))
  77. X#define max(x,y) (((x)>(y))?(x):(y))
  78. X
  79. Xvoid movemonst();
  80. Xvoid build_proximity_ripple();
  81. Xvoid move_scared();
  82. Xvoid move_smart();
  83. Xvoid move_dumb();
  84. Xvoid mmove();
  85. X
  86. X# define IDISTNORM   8  /* was 17 - dgk */
  87. X# define IDISTAGGR  20  /* was 40 - dgk */
  88. X
  89. Xstatic short w1[9],w1x[9],w1y[9];
  90. Xstatic int tmp1,tmp2,tmp3,tmp4,distance;
  91. X
  92. X/* list of monsters to move */
  93. Xstatic struct foo { char x ; char y; char smart; } movelist[250] ;
  94. X
  95. X/*
  96. X *  movemonst()     Routine to move the monsters toward the player
  97. X *
  98. X *  This routine has the responsibility to determine which monsters are to
  99. X *  move, and call movemt() to do the move.
  100. X *  Returns no value.
  101. X */
  102. Xvoid movemonst()
  103. X    {
  104. X    register int i,j,movecnt=0, smart_count, min_int ;
  105. X
  106. X    if (c[TIMESTOP]) return;    /* no action if time is stopped */
  107. X    if (c[HASTESELF])  if ((c[HASTESELF]&1)==0)  return;
  108. X    if (spheres) movsphere();   /* move the spheres of annihilation if any */
  109. X    if (c[HOLDMONST])  return;  /* no action if monsters are held */
  110. X
  111. X    if (c[AGGRAVATE])   /* determine window of monsters to move */
  112. X      {
  113. X      tmp1=playery-5; tmp2=playery+6; tmp3=playerx-10; tmp4=playerx+11;
  114. X      distance=IDISTAGGR; /* depth of intelligent monster movement */
  115. X      }
  116. X    else
  117. X      {
  118. X      tmp1=playery-3; tmp2=playery+4; tmp3=playerx-5; tmp4=playerx+6;
  119. X      distance=IDISTNORM; /* depth of intelligent monster movement */
  120. X      }
  121. X
  122. X    if (level == 0) /* if on outside level monsters can move in perimeter */
  123. X        {
  124. X        if (tmp1 < 0) tmp1=0;        if (tmp2 > MAXY) tmp2=MAXY;
  125. X        if (tmp3 < 0) tmp3=0;        if (tmp4 > MAXX) tmp4=MAXX;
  126. X        }
  127. X    else /* if in a dungeon monsters can't be on the perimeter (wall there) */
  128. X        {
  129. X        if (tmp1 < 1) tmp1=1;        if (tmp2 > MAXY-1) tmp2=MAXY-1;
  130. X        if (tmp3 < 1) tmp3=1;        if (tmp4 > MAXX-1) tmp4=MAXX-1;
  131. X        }
  132. X
  133. X    /* We now have a window in which to move monsters.  First find all
  134. X       monsters in the window, then decide whether or not to move them.
  135. X       Its faster that way since the size of the window is usually larger
  136. X       than the # of monsters in that window.
  137. X
  138. X       Find all monsters in the window.  The only time a monster cannot
  139. X       move is if: monsters are not aggrevated, AND player is stealthed,
  140. X       AND the monster is asleep due to stealth.  Split into two
  141. X       separate loops in order to simplify the if statement inside the
  142. X       loop for the most common case.
  143. X
  144. X       Also count # of smart monsters.
  145. X    */
  146. X    smart_count = 0 ;
  147. X    min_int = 10 - c[HARDGAME] ;    /* minimum monster intelligence to move smart */
  148. X    if ( c[AGGRAVATE] || !c[STEALTH] )
  149. X        {
  150. X        for ( j = tmp1 ; j < tmp2 ; j++ )
  151. X            for ( i = tmp3 ; i < tmp4 ; i++ )
  152. X                if (mitem[i][j])
  153. X                    {
  154. X                    movelist[movecnt].x = i;
  155. X                    movelist[movecnt].y = j ;
  156. X                    if ( monster[mitem[i][j]].intelligence > min_int )
  157. X                        {
  158. X                        movelist[movecnt].smart = TRUE ;
  159. X                        smart_count++;
  160. X                        }
  161. X                    else
  162. X                        movelist[movecnt].smart = FALSE ;
  163. X                    movecnt++;
  164. X                    }
  165. X        }
  166. X    else
  167. X        {
  168. X        for ( j = tmp1; j < tmp2 ; j++ )
  169. X            for ( i = tmp3 ; i < tmp4 ; i++ )
  170. X                if ( mitem[i][j] && stealth[i][j] )   /* stealth[x][y] = 1 when AWAKE! */
  171. X                    {
  172. X                    movelist[movecnt].x = i;
  173. X                    movelist[movecnt].y = j ;
  174. X                    if ( monster[mitem[i][j]].intelligence > min_int )
  175. X                        {
  176. X                        movelist[movecnt].smart = TRUE ;
  177. X                        smart_count++;
  178. X                        }
  179. X                    else
  180. X                        movelist[movecnt].smart = FALSE ;
  181. X                    movecnt++;
  182. X                    }
  183. X        }
  184. X
  185. X    /* now move the monsters in the movelist.  If we have at least one
  186. X       smart monster, build a proximity ripple and use it for all smart
  187. X       monster movement.
  188. X    */
  189. X    if (movecnt > 0 )
  190. X        {
  191. X        if ( c[SCAREMONST] )
  192. X            for ( i = 0 ; i < movecnt ; i++ )
  193. X                move_scared( movelist[i].x, movelist[i].y );
  194. X        else
  195. X            {
  196. X            if ( smart_count > 0 )
  197. X                {
  198. X                /* I was going to put in code that prevented the rebuilding
  199. X                   of the proximity ripple if the player had not moved since
  200. X                   the last turn.  Unfortunately, this permits the player to
  201. X                   blast down doors to treasure rooms and not have a single
  202. X                   intelligent monster move.
  203. X                */
  204. X                build_proximity_ripple();
  205. X                for ( i = 0 ; i < movecnt ; i++ )
  206. X                    if ( movelist[i].smart )
  207. X                        move_smart( movelist[i].x, movelist[i].y );
  208. X                    else
  209. X                        move_dumb( movelist[i].x, movelist[i].y );
  210. X                }
  211. X            else
  212. X                for ( i = 0 ; i < movecnt ; i++ )
  213. X                    move_dumb( movelist[i].x, movelist[i].y );
  214. X            }
  215. X        }
  216. X
  217. X    /* Also check for the last monster hit.  This is necessary to prevent
  218. X       the player from getting free hits on a monster with long range
  219. X       spells or when stealthed.
  220. X    */
  221. X    if ( c[AGGRAVATE] || !c[STEALTH] )
  222. X        {
  223. X        /* If the last monster hit is within the move window, its already
  224. X           been moved.
  225. X        */
  226. X    if ( ( ( lasthx < tmp3 || lasthx >= tmp4 ) ||
  227. X           ( lasthy < tmp1 || lasthy >= tmp2 ) ) &&
  228. X           mitem[lasthx][lasthy] )
  229. X            {
  230. X        if ( c[SCAREMONST] )
  231. X                move_scared( lasthx, lasthy );
  232. X            else
  233. X        if ( monster[mitem[lasthx][lasthy]].intelligence > min_int )
  234. X                    {
  235. X            if ( smart_count == 0 )
  236. X                        build_proximity_ripple( );
  237. X                    move_smart( lasthx, lasthy );
  238. X                    }
  239. X                else
  240. X                    move_dumb( lasthx, lasthy );
  241. X            lasthx = w1x[0];   /* make sure the monster gets moved again */
  242. X            lasthy = w1y[0];
  243. X            }
  244. X        }
  245. X    else
  246. X        {
  247. X        /* If the last monster hit is within the move window, and not
  248. X           asleep due to stealth, then it has already been moved.
  249. X       Otherwise (monster outside window, asleep due to stealth),
  250. X       move the monster and update the lasthit x,y position.
  251. X        */
  252. X    if ( ( lasthx < tmp3 || lasthx >= tmp4 ) ||
  253. X             ( lasthy < tmp1 || lasthy >= tmp2 ) &&
  254. X       mitem[lasthx][lasthy] || !stealth[lasthx][lasthy] )
  255. X            {
  256. X        if ( c[SCAREMONST] )
  257. X                move_scared( lasthx, lasthy );
  258. X            else
  259. X        if ( monster[mitem[lasthx][lasthy]].intelligence > min_int )
  260. X                    {
  261. X            if ( smart_count == 0 )
  262. X                        build_proximity_ripple( );
  263. X                    move_smart( lasthx, lasthy );
  264. X                    }
  265. X                else
  266. X                    move_dumb( lasthx, lasthy );
  267. X            lasthx = w1x[0];   /* make sure the monster gets moved again */
  268. X            lasthy = w1y[0];
  269. X            }
  270. X        }
  271. X    }
  272. X
  273. Xstatic char screen[MAXX][MAXY];    /* proximity ripple storage */
  274. X
  275. X/* queue for breadth-first 'search' build of proximity ripple.
  276. X*/
  277. X#define MAX_QUEUE 100
  278. X    struct queue_entry
  279. X        {
  280. X        char x ;
  281. X        char y ;
  282. X        char distance ;
  283. X        } queue[MAX_QUEUE];
  284. X    int queue_head = 0 ;
  285. X    int queue_tail = 0 ;
  286. X
  287. X/* put a location on the proximity ripple queue
  288. X*/
  289. X#define PUTQUEUE( _x, _y, _d )          \
  290. X    {                                   \
  291. X    queue[queue_tail].x = (_x) ;        \
  292. X    queue[queue_tail].y = (_y) ;        \
  293. X    queue[queue_tail].distance = (_d);  \
  294. X    queue_tail++;                       \
  295. X    if (queue_tail == MAX_QUEUE)        \
  296. X        queue_tail = 0 ;                \
  297. X    }
  298. X
  299. X/* take a location from the proximity ripple queue
  300. X*/
  301. X#define GETQUEUE( _x, _y, _d )          \
  302. X    {                                   \
  303. X    (_x) = queue[queue_head].x ;        \
  304. X    (_y) = queue[queue_head].y ;        \
  305. X    (_d) = queue[queue_head].distance ; \
  306. X    queue_head++;                       \
  307. X    if (queue_head == MAX_QUEUE)        \
  308. X        queue_head = 0 ;                \
  309. X    }
  310. X
  311. X/* check for the proximity ripple queue being empty
  312. X*/
  313. X#define QUEUEEMPTY() (queue_head == queue_tail)
  314. X
  315. X/*
  316. X    For smart monster movement, build a proximity ripple from the player's
  317. X    position, out to a 'distance' of 20.  For example:
  318. X
  319. X    W 5 4 4 W W X    Player is at position marked 1
  320. X    W 5 W 3 3 W W    W is a wall.  Monsters will attempt
  321. X    W 6 W 2 W 4 W    to move to a location with a smaller
  322. X    W 7 W 1 W 5 W    value than their current position.
  323. X    W 8 W W W 6 W    Note that a monster at location X
  324. X    W 9 9 8 7 7 7    will not move at all.
  325. X    W W W 8 W W W
  326. X*/
  327. Xvoid build_proximity_ripple()
  328. X    {
  329. X    int xl, yl, xh, yh ;
  330. X    int k, m, z, tmpx, tmpy;
  331. X    int curx, cury, curdist;
  332. X
  333. X    xl=tmp3-2; yl=tmp1-2; xh=tmp4+2;  yh=tmp2+2;
  334. X    vxy(&xl,&yl);  vxy(&xh,&yh);
  335. X    for (k=yl; k<=yh; k++)
  336. X    for (m=xl; m<=xh; m++)
  337. X        {
  338. X        switch(item[m][k])
  339. X        {
  340. X        case OWALL:
  341. X        case OPIT:
  342. X        case OTRAPARROW:
  343. X        case ODARTRAP:
  344. X        case OCLOSEDDOOR:
  345. X        case OTRAPDOOR:
  346. X        case OTELEPORTER:
  347. X            screen[m][k]=127;
  348. X            break;
  349. X        default:
  350. X            screen[m][k] = 0;
  351. X            break;
  352. X        };
  353. X          }
  354. X      screen[playerx][playery]=1;
  355. X
  356. X/* now perform proximity ripple from playerx,playery to monster */
  357. X      xl=tmp3-1; yl=tmp1-1; xh=tmp4+1;  yh=tmp2+1;
  358. X      vxy(&xl,&yl);  vxy(&xh,&yh);
  359. X
  360. X      PUTQUEUE( playerx, playery, 1 );
  361. X      do
  362. X      {
  363. X      GETQUEUE( curx, cury, curdist );
  364. X
  365. X      /* test all spots around the current one being looked at.
  366. X      */
  367. X      if ( ( curx >= xl && curx < xh ) &&
  368. X           ( cury >= yl && cury < yh ) )
  369. X          {
  370. X          for (z=1; z<9; z++)
  371. X          {
  372. X          tmpx = curx + diroffx[z] ;
  373. X          tmpy = cury + diroffy[z] ;
  374. X          if (screen[tmpx][tmpy] == 0 )
  375. X              {
  376. X              screen[tmpx][tmpy] = curdist + 1;
  377. X              PUTQUEUE( tmpx, tmpy, curdist + 1 );
  378. X              }
  379. X          }
  380. X          }
  381. X      }
  382. X      while (!QUEUEEMPTY());
  383. X
  384. X    }
  385. X
  386. X/*
  387. X    Move scared monsters randomly away from the player position.
  388. X*/
  389. Xvoid move_scared( i, j )
  390. Xint i, j ;
  391. X    {
  392. X    int xl, yl, tmp, tmpitem ;
  393. X
  394. X    /* check for a half-speed monster, and check if not to move.  Could be
  395. X       done in the monster list build.
  396. X    */
  397. X    switch(mitem[i][j])
  398. X        {
  399. X        case TROGLODYTE:  case HOBGOBLIN:  case METAMORPH:  case XVART:
  400. X        case INVISIBLESTALKER:  case ICELIZARD: if ((gtime & 1) == 1) return;
  401. X        };
  402. X
  403. X    if ((xl = i+rnd(3)-2) < 0)
  404. X    xl=0;
  405. X    if (xl >= MAXX)
  406. X    xl=MAXX-1;
  407. X    if ((yl = j+rnd(3)-2) < 0)
  408. X    yl=0;
  409. X    if (yl >= MAXY)
  410. X    yl=MAXY-1;
  411. X
  412. X    if ((tmp=item[xl][yl]) != OWALL)
  413. X    if (mitem[xl][yl] == 0)
  414. X        if ((mitem[i][j] != VAMPIRE) || (tmp != OMIRROR))
  415. X        if (tmp != OCLOSEDDOOR)
  416. X            mmove(i,j,xl,yl);
  417. X    }
  418. X
  419. X/*
  420. X    Move monsters that are moving intelligently, using the proximity
  421. X    ripple.  Attempt to move to a position in the proximity ripple
  422. X    that is closer to the player.
  423. X
  424. X    Parameters: the X,Y position of the monster to be moved.
  425. X*/
  426. Xvoid move_smart( i, j )
  427. Xint i,j ;
  428. X    {
  429. X    int x,y,z ;
  430. X
  431. X    /* check for a half-speed monster, and check if not to move.  Could be
  432. X       done in the monster list build.
  433. X    */
  434. X    switch(mitem[i][j])
  435. X        {
  436. X        case TROGLODYTE:  case HOBGOBLIN:  case METAMORPH:  case XVART:
  437. X        case INVISIBLESTALKER:  case ICELIZARD: if ((gtime & 1) == 1) return;
  438. X        };
  439. X
  440. X    /* find an adjoining location in the proximity ripple that is
  441. X       closer to the player (has a lower value) than the monster's
  442. X       current position.
  443. X    */
  444. X    if (mitem[i][j] != VAMPIRE)
  445. X    for (z=1; z<9; z++) /* go around in a circle */
  446. X        {
  447. X        x = i + diroffx[z] ;
  448. X        y = j + diroffy[z] ;
  449. X        if ( screen[x][y] < screen[i][j] )
  450. X        if ( !mitem[x][y] )
  451. X            {
  452. X            mmove(i,j,w1x[0]=x,w1y[0]=y);
  453. X            return;
  454. X            }
  455. X        }
  456. X    else
  457. X    /* prevent vampires from moving onto mirrors
  458. X    */
  459. X    for (z=1; z<9; z++) /* go around in a circle */
  460. X        {
  461. X        x = i + diroffx[z] ;
  462. X        y = j + diroffy[z] ;
  463. X        if (( screen[x][y] < screen[i][j] ) &&
  464. X        ( item[x][y] != OMIRROR ))
  465. X        if ( !mitem[x][y] )
  466. X            {
  467. X            mmove(i,j,w1x[0]=x,w1y[0]=y);
  468. X            return;
  469. X            }
  470. X        }
  471. X
  472. X    }
  473. X
  474. X/*
  475. X   For monsters that are not moving in an intelligent fashion.  Move
  476. X   in a direct fashion toward the player's current position.
  477. X
  478. X   Parameters: the X,Y position of the monster to move.
  479. X*/
  480. Xvoid move_dumb( i, j )
  481. Xint i, j ;
  482. X    {
  483. X    int xl, yl, xh, yh ;
  484. X    int k, m, tmp, tmpd, tmpx, tmpy ;
  485. X
  486. X    /* check for a half-speed monster, and check if not to move.  Could be
  487. X       done in the monster list build.
  488. X    */
  489. X    switch(mitem[i][j])
  490. X        {
  491. X        case TROGLODYTE:  case HOBGOBLIN:  case METAMORPH:  case XVART:
  492. X        case INVISIBLESTALKER:  case ICELIZARD: if ((gtime & 1) == 1) return;
  493. X        };
  494. X
  495. X    /* dumb monsters move here */
  496. X    /* set up range of spots to check.  instead of checking all points
  497. X       around the monster, only check those closest to the player.  For
  498. X       example, if the player is up and right of the monster, check only
  499. X       the three spots up and right of the monster.
  500. X    */
  501. X    xl=i-1;  yl=j-1;  xh=i+2;  yh=j+2;
  502. X    if (i<playerx) xl++; else if (i>playerx) --xh;
  503. X    if (j<playery) yl++; else if (j>playery) --yh;
  504. X
  505. X    /* check all spots in the range.  find the one that is closest to
  506. X       the player.  if the monster is already next to the player, exit
  507. X       the check immediately.
  508. X    */
  509. X    tmpd = 10000 ;
  510. X    tmpx = i ;  tmpy = j ;
  511. X    for ( k = xl ; k < xh ; k++ )
  512. X    for ( m = yl ; m < yh ; m++ )
  513. X        if ( k == playerx && m == playery )
  514. X        {
  515. X        tmpd = 1 ;
  516. X        tmpx = k ;
  517. X        tmpy = m ;
  518. X        break;       /* exitloop */
  519. X        }
  520. X        else if ((item[k][m] != OWALL) &&
  521. X             (item[k][m] != OCLOSEDDOOR) &&
  522. X             ((mitem[k][m] == 0 ) || (( k == i ) && ( m == j ))) &&
  523. X             ((mitem[i][j] != VAMPIRE) || (item[k][m] != OMIRROR)))
  524. X        {
  525. X        tmp = (playerx-k)*(playerx-k)+(playery-m)*(playery-m);
  526. X        if (tmp < tmpd)
  527. X            {
  528. X            tmpd = tmp;
  529. X            tmpx = k;
  530. X            tmpy = m;
  531. X            }  /* end if */
  532. X        }  /* end if */
  533. X
  534. X    /* we have finished checking the spaces around the monster.  if
  535. X       any can be moved on and are closer to the player than the
  536. X       current location, move the monster.
  537. X    */
  538. X    if ((tmpd < 10000) && ((tmpx != i) || (tmpy != j)))
  539. X    {
  540. X    mmove( i, j, tmpx, tmpy );
  541. X    w1x[0] = tmpx ;              /* for last monster hit */
  542. X    w1y[0] = tmpy ;
  543. X    }
  544. X    else
  545. X    {
  546. X    w1x[0] = i ;              /* for last monster hit */
  547. X    w1y[0] = j ;
  548. X    }
  549. X    }  /* end move_dumb() */
  550. X
  551. X/*
  552. X *  mmove(x,y,xd,yd)    Function to actually perform the monster movement
  553. X *      int x,y,xd,yd;
  554. X *
  555. X *  Enter with the from coordinates in (x,y) and the destination coordinates
  556. X *  in (xd,yd).
  557. X */
  558. Xvoid mmove(aa,bb,cc,dd)
  559. X    int aa,bb,cc,dd;
  560. X    {
  561. X    register int tmp,i,flag;
  562. X    char *who,*p;
  563. X    flag=0; /* set to 1 if monster hit by arrow trap */
  564. X    if ((cc==playerx) && (dd==playery))
  565. X        {
  566. X        hitplayer(aa,bb);
  567. X        return;
  568. X        }
  569. X    i=item[cc][dd];
  570. X    if ((i==OPIT) || (i==OTRAPDOOR))
  571. X      switch(mitem[aa][bb])
  572. X        {
  573. X    case BAT:           case EYE:
  574. X    case SPIRITNAGA:    case PLATINUMDRAGON:    case WRAITH:
  575. X        case VAMPIRE:       case SILVERDRAGON:      case POLTERGEIST:
  576. X        case DEMONLORD:     case DEMONLORD+1:       case DEMONLORD+2:
  577. X        case DEMONLORD+3:   case DEMONLORD+4:       case DEMONLORD+5:
  578. X        case DEMONLORD+6:   case DEMONPRINCE:   break;
  579. X
  580. X        default:    mitem[aa][bb]=0; /* fell in a pit or trapdoor */
  581. X        };
  582. X    tmp = mitem[aa][bb];
  583. X    mitem[cc][dd] = tmp;
  584. X    if (i==OANNIHILATION)
  585. X        {
  586. X        if (tmp>=DEMONLORD+3) /* demons dispel spheres */
  587. X            {
  588. X            cursors();
  589. X            lprintf("\nThe %s dispels the sphere!",monster[tmp].name);
  590. X            rmsphere(cc,dd);    /* delete the sphere */
  591. X            }
  592. X        else mitem[cc][dd]=i=tmp=0;
  593. X        }
  594. X    stealth[cc][dd]=1;
  595. X    if ((hitp[cc][dd] = hitp[aa][bb]) < 0) hitp[cc][dd]=1;
  596. X    mitem[aa][bb] = 0;              
  597. X    if (tmp == LEPRECHAUN)
  598. X        switch(i)
  599. X            {
  600. X            case OGOLDPILE:  case OMAXGOLD:  case OKGOLD:  case ODGOLD:
  601. X            case ODIAMOND:   case ORUBY:     case OEMERALD: case OSAPPHIRE:
  602. X                    item[cc][dd] = 0; /* leprechaun takes gold */
  603. X            };
  604. X
  605. X    if (tmp == TROLL)  /* if a troll regenerate him */
  606. X        if ((gtime & 1) == 0)
  607. X            if (monster[tmp].hitpoints > hitp[cc][dd])  hitp[cc][dd]++;
  608. X
  609. X    if (i==OTRAPARROW)  /* arrow hits monster */
  610. X        { who = "An arrow";  if ((hitp[cc][dd] -= rnd(10)+level) <= 0)
  611. X            { mitem[cc][dd]=0;  flag=2; } else flag=1; }
  612. X    if (i==ODARTRAP)    /* dart hits monster */
  613. X        { who = "A dart";  if ((hitp[cc][dd] -= rnd(6)) <= 0)
  614. X            { mitem[cc][dd]=0;  flag=2; } else flag=1; }
  615. X    if (i==OTELEPORTER) /* monster hits teleport trap */
  616. X        { flag=3; fillmonst(mitem[cc][dd]);  mitem[cc][dd]=0; }
  617. X    if (c[BLINDCOUNT]) return;  /* if blind don't show where monsters are   */
  618. X# ifdef DGK
  619. X    if (know[cc][dd] & HAVESEEN) 
  620. X# else
  621. X    if (know[cc][dd] & 1) 
  622. X# endif
  623. X        {
  624. X        p=0;
  625. X        if (flag) cursors();
  626. X        switch(flag)
  627. X          {
  628. X          case 1: p="\n%s hits the %s";  break;
  629. X          case 2: p="\n%s hits and kills the %s";  break;
  630. X          case 3: p="\nThe %s%s gets teleported"; who="";  break;
  631. X          };
  632. X        if (p) { lprintf(p,who,monster[tmp].name); beep(); }
  633. X        }
  634. X/*  if (yrepcount>1) { know[aa][bb] &= 2;  know[cc][dd] &= 2; return; } */
  635. X# ifdef DGK
  636. X    if (know[aa][bb] & HAVESEEN)   show1cell(aa,bb);
  637. X    if (know[cc][dd] & HAVESEEN)   show1cell(cc,dd);
  638. X# else
  639. X    if (know[aa][bb] & 1)   show1cell(aa,bb);
  640. X    if (know[cc][dd] & 1)   show1cell(cc,dd);
  641. X# endif
  642. X    }
  643. END_OF_FILE
  644. if test 18818 -ne `wc -c <'movem.c'`; then
  645.     echo shar: \"'movem.c'\" unpacked with wrong size!
  646. fi
  647. # end of 'movem.c'
  648. fi
  649. if test -f 'savelev.c' -a "${1}" != "-c" ; then 
  650.   echo shar: Will not clobber existing file \"'savelev.c'\"
  651. else
  652. echo shar: Extracting \"'savelev.c'\" \(3594 characters\)
  653. sed "s/^X//" >'savelev.c' <<'END_OF_FILE'
  654. X/* savelev.c         Larn is copyrighted 1986 by Noah Morgan. */
  655. X#include "header.h"
  656. X
  657. X# ifdef MSDOS
  658. X
  659. Xextern int swapfd;        /* swap file file descriptor */
  660. X
  661. X
  662. XDISKBLOCK *
  663. Xgetfreediskblk()
  664. X{
  665. X    DISKBLOCK    *dp;
  666. X
  667. X    for (dp = diskblks; dp; dp = dp->next)
  668. X        if (dp->level == FREEBLOCK)
  669. X            return dp;
  670. X    levelinfo();
  671. X    error("Can't find a free disk block ?\n");
  672. X}
  673. X
  674. XRAMBLOCK *
  675. Xgetramblk(lev)
  676. X{
  677. X    RAMBLOCK    *rp, *orp;
  678. X    DISKBLOCK    *dp;
  679. X    long        otime;
  680. X    unsigned int    bytes;
  681. X
  682. X    /* Check if the level is in memory already.
  683. X     */
  684. X    for (rp = ramblks; rp; rp = rp->next)
  685. X        if (rp->level == lev)
  686. X            return rp;
  687. X
  688. X    /* Else grab the first available one.
  689. X     */
  690. X    for (rp = ramblks; rp; rp = rp->next)
  691. X        if (rp->level == FREEBLOCK)
  692. X            return rp;
  693. X
  694. X    /* No ramblocks free, so swap out the oldest level
  695. X     */
  696. X    dp = getfreediskblk();
  697. X
  698. X# ifdef ndef
  699. Xwarn("\nTrying to swap\n");
  700. X# endif
  701. X
  702. X    /* Find the oldest level for swapping out.
  703. X     */
  704. X    otime = ramblks->gtime;
  705. X    orp = ramblks;
  706. X    for (rp = ramblks->next; rp; rp = rp->next) {
  707. X        if (rp->gtime < otime) {
  708. X            otime = rp->gtime;
  709. X            orp = rp;
  710. X        }
  711. X    }
  712. X
  713. X    /* Send the oldest level out to disk.
  714. X     */
  715. X    if (lseek(swapfd, dp->fpos, 0) < 0)
  716. X        error("Can't seek to %ld\n", dp->fpos);
  717. X
  718. X    bytes = sizeof rp->cell;
  719. X    if (write(swapfd, (char *) orp->cell, bytes) != bytes)
  720. X        error("Out of space writing swap file !\n");
  721. X
  722. X    /* Update the level information
  723. X     */
  724. X    dp->level = orp->level;
  725. X    dp->gtime = orp->gtime;
  726. X    orp->level = FREEBLOCK;
  727. X# ifdef ndef
  728. Xwarn("Successful swap\n");
  729. X# endif
  730. X    return orp;
  731. X}
  732. X
  733. X
  734. X# endif
  735. X
  736. X/*
  737. X *    routine to save the present level into storage
  738. X */
  739. Xsavelevel()
  740. X    {
  741. X    register struct cel *pcel;
  742. X    register char *pitem,*pknow,*pmitem;
  743. X    register short *phitp,*piarg;
  744. X    register struct cel *pecel;
  745. X
  746. X# ifdef MSDOS
  747. X    RAMBLOCK    *rp;
  748. X
  749. X    rp = getramblk(level);
  750. X    pcel = rp->cell;
  751. X    rp->gtime = gtime;
  752. X    rp->level = level;
  753. X# else
  754. X    pcel = &cell[level*MAXX*MAXY];    /* pointer to this level's cells */
  755. X# endif
  756. X    pecel = pcel + MAXX*MAXY;    /* pointer to past end of this level's cells */
  757. X    pitem=item[0]; piarg=iarg[0]; pknow=know[0]; pmitem=mitem[0]; phitp=hitp[0];
  758. X    while (pcel < pecel)
  759. X        {
  760. X        pcel->mitem  = *pmitem++;
  761. X        pcel->hitp   = *phitp++;
  762. X        pcel->item   = *pitem++;
  763. X        pcel->know   = *pknow++;
  764. X        pcel->iarg   = *piarg++;
  765. X        pcel++;
  766. X        }
  767. X    }
  768. X
  769. X
  770. X/*
  771. X *    routine to restore a level from storage
  772. X */
  773. Xgetlevel()
  774. X    {
  775. X    register struct cel *pcel;
  776. X    register char *pitem,*pknow,*pmitem;
  777. X    register short *phitp,*piarg;
  778. X    register struct cel *pecel;
  779. X
  780. X# ifdef MSDOS
  781. X    RAMBLOCK    *rp;
  782. X    DISKBLOCK    *dp;
  783. X    unsigned int    bytes;
  784. X
  785. X    /* Is the level in memory already ?
  786. X     */
  787. X    for (rp = ramblks; rp; rp = rp->next)
  788. X        if (rp->level == level)
  789. X            goto haverp;
  790. X
  791. X    /* Is it on disk ?
  792. X     */
  793. X    for (dp = diskblks; dp; dp = dp->next)
  794. X        if (dp->level == level)
  795. X            break;
  796. X    if (dp == NULL) {
  797. X        levelinfo();
  798. X        error("Level %d is neither in memory nor on disk\n", level);
  799. X    }
  800. X
  801. X    /* Make room for it and read it in.
  802. X     */
  803. X    rp = getramblk(level);
  804. X    if (lseek(swapfd, dp->fpos, 0) < 0)
  805. X        error("Can't seek to %ld\n", dp->fpos);
  806. X    bytes = sizeof rp->cell;
  807. X    if (read(swapfd, (char *) rp->cell, bytes) != bytes)
  808. X        error("Didn't read %u bytes\n", bytes);
  809. X
  810. X    /* The disk space is available for future swaps.
  811. X     */
  812. X    dp->level = FREEBLOCK;
  813. Xhaverp:
  814. X    pcel = rp->cell;
  815. X    rp->level = FREEBLOCK;
  816. X# else
  817. X    pcel = &cell[level*MAXX*MAXY];    /* pointer to this level's cells */
  818. X# endif
  819. X    pecel = pcel + MAXX*MAXY;    /* pointer to past end of this level's cells */
  820. X    pitem=item[0]; piarg=iarg[0]; pknow=know[0]; pmitem=mitem[0]; phitp=hitp[0];
  821. X    while (pcel < pecel)
  822. X        {
  823. X        *pmitem++ = pcel->mitem;
  824. X        *phitp++ = pcel->hitp;
  825. X        *pitem++ = pcel->item;
  826. X        *pknow++ = pcel->know;
  827. X        *piarg++ = pcel->iarg;
  828. X        pcel++;
  829. X        }
  830. X    }
  831. END_OF_FILE
  832. if test 3594 -ne `wc -c <'savelev.c'`; then
  833.     echo shar: \"'savelev.c'\" unpacked with wrong size!
  834. fi
  835. # end of 'savelev.c'
  836. fi
  837. if test -f 'spells.c' -a "${1}" != "-c" ; then 
  838.   echo shar: Will not clobber existing file \"'spells.c'\"
  839. else
  840. echo shar: Extracting \"'spells.c'\" \(27476 characters\)
  841. sed "s/^X//" >'spells.c' <<'END_OF_FILE'
  842. X/*
  843. X  cast()             Subroutine called by parse to cast a spell for the user
  844. X  speldamage(x)      Function to perform spell functions cast by the player
  845. X  loseint()          Routine to decrement your int (intelligence) if > 3
  846. X  isconfuse()        Routine to check to see if player is confused
  847. X  nospell(x,monst)   Routine to return 1 if a spell doesn't affect a monster
  848. X  fullhit(xx)        Function to return full damage against a monst (aka web)
  849. X  direct(spnum,dam,str,arg)   Routine to direct spell damage 1 square in 1 dir
  850. X  godirect(spnum,dam,str,delay,cshow)     Function to perform missile attacks
  851. X  ifblind(x,y)       Routine to put "monster" or the monster name into lastmosnt
  852. X  tdirect(spnum)     Routine to teleport away a monster
  853. X  omnidirect(sp,dam,str)  Routine to damage all monsters 1 square from player
  854. X  dirsub(x,y)        Routine to ask for direction, then modify x,y for it
  855. X  dirpoly(spnum)     Routine to ask for a direction and polymorph a monst
  856. X  annihilate()   Routine to annihilate monsters around player, playerx,playery
  857. X  genmonst()         Function to ask for monster and genocide from game
  858. X*/
  859. X
  860. X#include "header.h"
  861. X#include <ctype.h>
  862. X
  863. X#define min(x,y) (((x)>(y))?(y):(x))
  864. X#define max(x,y) (((x)>(y))?(x):(y))
  865. X
  866. Xstruct isave    /* used for altar reality */
  867. X    {
  868. X    char type;  /* 0=item,  1=monster */
  869. X    char id;    /* item number or monster number */
  870. X    short arg;  /* the type of item or hitpoints of monster */
  871. X    };
  872. X
  873. X/* Forward declarations
  874. X*/
  875. Xstatic void create_guardian();
  876. Xextern hitm();
  877. X
  878. X/*
  879. X *  cast()      Subroutine called by parse to cast a spell for the user
  880. X *
  881. X *  No arguments and no return value.
  882. X */
  883. Xstatic char eys[] = "\nEnter your spell: ";
  884. Xcast()
  885. X    {
  886. X    register int i,j,a,b,d;
  887. X    cursors();
  888. X    if (c[SPELLS]<=0) 
  889. X        {   
  890. X        lprcat("\nYou don't have any spells!"); 
  891. X        return; 
  892. X        }
  893. X    lprcat(eys);
  894. X    --c[SPELLS];
  895. X    while ((a=ttgetch())=='I')
  896. X        { 
  897. X        seemagic(-1); 
  898. X        cursors();  
  899. X        lprcat(eys);
  900. X        }
  901. X    if (a=='\33') 
  902. X        goto over;                  /*  to escape casting a spell   */
  903. X    if ((b=ttgetch())=='\33') 
  904. X        goto over;                  /*  to escape casting a spell   */
  905. X    if ((d=ttgetch())=='\33')
  906. X        { 
  907. Xover: 
  908. X        lprcat(aborted); 
  909. X        c[SPELLS]++; 
  910. X        return;
  911. X        }                           /*  to escape casting a spell   */
  912. X#ifdef EXTRA
  913. X    c[SPELLSCAST]++;
  914. X#endif
  915. X    for (lprc('\n'),j= -1,i=0; i<SPNUM; i++) /*seq search for his spell, hash?*/
  916. X        if ((spelcode[i][0]==a) && (spelcode[i][1]==b) && (spelcode[i][2]==d))
  917. X            if (spelknow[i])
  918. X                {  speldamage(i);  j = 1;  i=SPNUM; }
  919. X
  920. X    if (j == -1) lprcat("  Nothing Happened ");
  921. X    bottomline();
  922. X    }
  923. X
  924. X/*
  925. X *  speldamage(x)       Function to perform spell functions cast by the player
  926. X *      int x;
  927. X *
  928. X *  Enter with the spell number, returns no value.
  929. X *  Please insure that there are 2 spaces before all messages here
  930. X */
  931. Xstatic speldamage(x)
  932. X    int x;
  933. X    {
  934. X    register int i,j,clev;
  935. X    int xl,xh,yl,yh;
  936. X    register char *p,*kn,*pm;
  937. X
  938. X    if (x>=SPNUM) return;   /* no such spell */
  939. X    if (c[TIMESTOP])  { lprcat("  It didn't seem to work"); return; }  /* not if time stopped */
  940. X    clev = c[LEVEL];
  941. X    if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
  942. X        { lprcat("  It didn't work!");  return; }
  943. X    if (clev*3+2 < x)
  944. X    {
  945. X    lprcat("  Nothing happens.  You seem inexperienced at this");
  946. X    return;
  947. X    }
  948. X
  949. X    switch(x)
  950. X        {
  951. X/* ----- LEVEL 1 SPELLS ----- */
  952. X
  953. X        case 0: if (c[PROTECTIONTIME]==0)   c[MOREDEFENSES]+=2; /* protection field +2 */
  954. X                c[PROTECTIONTIME] += 250;   return;
  955. X
  956. X        case 1: i = rnd(((clev+1)<<1)) + clev + 3;
  957. X                godirect(x,i,(clev>=2)?"  Your missiles hit the %s":"  Your missile hit the %s",100,'+'); /* magic missile */
  958. X
  959. X                return;
  960. X
  961. X        case 2: if (c[DEXCOUNT]==0) c[DEXTERITY]+=3; /* dexterity   */
  962. X                c[DEXCOUNT] += 400;     return;
  963. X
  964. X        case 3: i=rnd(3)+1;
  965. X                p="  While the %s slept, you smashed it %d times";
  966. X            ws: direct(x,fullhit(i),p,i); /*    sleep   */  return;
  967. X
  968. X        case 4: /*  charm monster   */  c[CHARMCOUNT] += c[CHARISMA]<<1;    return;
  969. X
  970. X        case 5: godirect(x,rnd(10)+15+clev,"  The sound damages the %s",70,'@'); /* sonic spear */
  971. X                return;
  972. X
  973. X/* ----- LEVEL 2 SPELLS ----- */
  974. X
  975. X        case 6: i=rnd(3)+2; p="  While the %s is entangled, you hit %d times";
  976. X                goto ws; /* web */
  977. X
  978. X        case 7: if (c[STRCOUNT]==0) c[STREXTRA]+=3; /*  strength    */
  979. X                c[STRCOUNT] += 150+rnd(100);    return;
  980. X
  981. X        case 8: yl = playery-5;     /* enlightenment */
  982. X                yh = playery+6;   xl = playerx-15;   xh = playerx+16;
  983. X                vxy(&xl,&yl);   vxy(&xh,&yh); /* check bounds */
  984. X                for (i=yl; i<=yh; i++) /* enlightenment */
  985. X# ifdef DGK
  986. X                    for (j=xl; j<=xh; j++)
  987. X                        know[j][i]=KNOWALL;
  988. X# else
  989. X                    for (j=xl; j<=xh; j++)  know[j][i]=1;
  990. X# endif
  991. X                draws(xl,xh+1,yl,yh+1); return;
  992. X
  993. X        case 9: raisehp(20+(clev<<1));  return;  /* healing */
  994. X
  995. X        case 10:    c[BLINDCOUNT]=0;    return; /* cure blindness   */
  996. X
  997. X        case 11:    createmonster(makemonst(level+1)+8);  return;
  998. X
  999. X        case 12:    if (rnd(11)+7 <= c[WISDOM]) direct(x,rnd(20)+20+clev,"  The %s believed!",0);
  1000. X                    else lprcat("  It didn't believe the illusions!");
  1001. X                    return;
  1002. X
  1003. X        case 13:    /* if he has the amulet of invisibility then add more time */
  1004. X                    for (j=i=0; i<26; i++)
  1005. X                        if (iven[i]==OAMULET) j+= 1+ivenarg[i];
  1006. X                    c[INVISIBILITY] += (j<<7)+12;   return;
  1007. X
  1008. X/* ----- LEVEL 3 SPELLS ----- */
  1009. X
  1010. X        case 14:    godirect(x,rnd(25+clev)+25+clev,"  The fireball hits the %s",40,'*'); return; /*    fireball */
  1011. X
  1012. X        case 15:    godirect(x,rnd(25)+20+clev,"  Your cone of cold strikes the %s",60,'O');    /*  cold */
  1013. X                    return;
  1014. X
  1015. X        case 16:    dirpoly(x);  return;    /*  polymorph */
  1016. X
  1017. X        case 17:    c[CANCELLATION]+= 5+clev;   return; /*  cancellation    */
  1018. X
  1019. X        case 18:    c[HASTESELF]+= 7+clev;  return;  /* haste self  */
  1020. X
  1021. X        case 19:    omnidirect(x,30+rnd(10),"  The %s gasps for air");  /* cloud kill */
  1022. X                    return;
  1023. X
  1024. X        case 20:    xh = min(playerx+1,MAXX-2);     yh = min(playery+1,MAXY-2);
  1025. X                    for (i=max(playerx-1,1); i<=xh; i++) /* vaporize rock */
  1026. X                      for (j=max(playery-1,1); j<=yh; j++)
  1027. X                        {
  1028. X                        kn = &know[i][j];
  1029. X                            pm = &mitem[i][j];
  1030. X                        switch(*(p= &item[i][j]))
  1031. X                          {
  1032. X                          case OWALL: if (level < MAXLEVEL+MAXVLEVEL-1)
  1033. X                                            *p = *kn = 0;
  1034. X                                        break;
  1035. X
  1036. X                          case OSTATUE: if (c[HARDGAME]<3)
  1037. X                                             {
  1038. X                                             *p=OBOOK; iarg[i][j]=level;  *kn=0;
  1039. X                                             }
  1040. X                                        break;
  1041. X
  1042. X              case OTHRONE:
  1043. X                  *p= OTHRONE2;
  1044. X                  create_guardian( GNOMEKING, i, j );
  1045. X                  break;
  1046. X
  1047. X              case OALTAR:
  1048. X                  create_guardian( DEMONPRINCE, i, j );
  1049. X                  break;
  1050. X
  1051. X              case OFOUNTAIN:
  1052. X                  create_guardian( WATERLORD, i, j );
  1053. X                  break;
  1054. X              };
  1055. X                        switch(*pm)
  1056. X                            {
  1057. X                            case XORN:  ifblind(i,j);  hitm(i,j,200); break; /* Xorn takes damage from vpr */
  1058. X                            }
  1059. X                        }
  1060. X                    return;
  1061. X
  1062. X/* ----- LEVEL 4 SPELLS ----- */
  1063. X
  1064. X        case 21:    direct(x,100+clev,"  The %s shrivels up",0); /* dehydration */
  1065. X                    return;
  1066. X
  1067. X        case 22:    godirect(x,rnd(25)+20+(clev<<1),"  A lightning bolt hits the %s",1,'~');    /*  lightning */
  1068. X                    return;
  1069. X
  1070. X        case 23:    i=min(c[HP]-1,c[HPMAX]/2);  /* drain life */
  1071. X                    direct(x,i+i,"",0); c[HP] -= i;     return;
  1072. X
  1073. X        case 24:    if (c[GLOBE]==0) c[MOREDEFENSES] += 10;
  1074. X                    c[GLOBE] += 200;  loseint();  /* globe of invulnerability */
  1075. X                    return;
  1076. X
  1077. X        case 25:    omnidirect(x,32+clev,"  The %s struggles for air in your flood!"); /* flood */
  1078. X                    return;
  1079. X
  1080. X        case 26:    if (rnd(151)==63) { beep(); lprcat("\nYour heart stopped!\n"); nap(4000);  died(270); return; }
  1081. X                    if (c[WISDOM]>rnd(10)+10) direct(x,2000,"  The %s's heart stopped",0); /* finger of death */
  1082. X                    else lprcat("  It didn't work"); return;
  1083. X
  1084. X/* ----- LEVEL 5 SPELLS ----- */
  1085. X
  1086. X        case 27:    c[SCAREMONST] += rnd(10)+clev;  return;  /* scare monster */
  1087. X
  1088. X        case 28:    c[HOLDMONST] += rnd(10)+clev;  return;  /* hold monster */
  1089. X
  1090. X        case 29:    c[TIMESTOP] += rnd(20)+(clev<<1);  return;  /* time stop */
  1091. X
  1092. X        case 30:    tdirect(x);  return;  /* teleport away */
  1093. X
  1094. X        case 31:    omnidirect(x,35+rnd(10)+clev,"  The %s cringes from the flame"); /* magic fire */
  1095. X                    return;
  1096. X
  1097. X/* ----- LEVEL 6 SPELLS ----- */
  1098. X
  1099. X        case 32:    if ((rnd(23)==5) && (wizard==0)) /* sphere of annihilation */
  1100. X                        {
  1101. X                        beep(); lprcat("\nYou have been enveloped by the zone of nothingness!\n");
  1102. X                        nap(4000);  died(258); return;
  1103. X                        }
  1104. X                    xl=playerx; yl=playery;
  1105. X                    loseint();
  1106. X                    i=dirsub(&xl,&yl); /* get direction of sphere */
  1107. X                    newsphere(xl,yl,i,rnd(20)+11);  /* make a sphere */
  1108. X                    return;
  1109. X
  1110. X        case 33:    genmonst();  spelknow[33]=0;  /* genocide */
  1111. X                    loseint();
  1112. X                    return;
  1113. X
  1114. X        case 34:    /* summon demon */
  1115. X                    if (rnd(100) > 30) { direct(x,150,"  The demon strikes at the %s",0);  return; }
  1116. X                    if (rnd(100) > 15) { lprcat("  Nothing seems to have happened");  return; }
  1117. X                    lprcat("  The demon turned on you and vanished!"); beep();
  1118. X                    i=rnd(40)+30;  lastnum=277;
  1119. X                    losehp(i); /* must say killed by a demon */ return;
  1120. X
  1121. X        case 35:    /* walk through walls */
  1122. X                    c[WTW] += rnd(10)+5;    return;
  1123. X
  1124. X        case 36:    /* alter reality */
  1125. X                    {
  1126. X                    struct isave *save; /* pointer to item save structure */
  1127. X                    int sc; sc=0;   /* # items saved */
  1128. X                    save = (struct isave *)malloc(sizeof(struct isave)*MAXX*MAXY*2);
  1129. X            if (save == NULL)
  1130. X            {
  1131. X            lprcat("\nPolinneaus won't let you mess with his dungeon!");
  1132. X            return;
  1133. X            }
  1134. X            for (j=0; j<MAXY; j++)
  1135. X                        for (i=0; i<MAXX; i++) /* save all items and monsters */
  1136. X                            {
  1137. X                            xl = item[i][j];
  1138. X                            if (xl && xl!=OWALL && xl!=OANNIHILATION) 
  1139. X                                {
  1140. X                                save[sc].type=0;  save[sc].id=item[i][j];
  1141. X                                save[sc++].arg=iarg[i][j];
  1142. X                                }
  1143. X                            if (mitem[i][j]) 
  1144. X                                {
  1145. X                                save[sc].type=1;  save[sc].id=mitem[i][j];
  1146. X                                save[sc++].arg=hitp[i][j];
  1147. X                                }
  1148. X                            item[i][j]=OWALL;   mitem[i][j]=0;
  1149. X# ifdef DGK
  1150. X                        if (wizard)
  1151. X                            know[i][j]=KNOWALL;
  1152. X                        else
  1153. X                            know[i][j]=0;
  1154. X# else
  1155. X                            if (wizard) know[i][j]=1; else know[i][j]=0;
  1156. X# endif
  1157. X                            }
  1158. X                    eat(1,1);   if (level==1) item[33][MAXY-1]=0;
  1159. X                    for (j=rnd(MAXY-2), i=1; i<MAXX-1; i++) item[i][j]=0;
  1160. X                    while (sc>0) /* put objects back in level */
  1161. X                        {
  1162. X                        --sc;
  1163. X                        if (save[sc].type == 0)
  1164. X                            {
  1165. X                            int trys;
  1166. X                            for (trys=100, i=j=1; --trys>0 && item[i][j]; i=rnd(MAXX-1), j=rnd(MAXY-1));
  1167. X                            if (trys) { item[i][j]=save[sc].id; iarg[i][j]=save[sc].arg; }
  1168. X                            }
  1169. X                        else
  1170. X                            { /* put monsters back in */
  1171. X                            int trys;
  1172. X                            for (trys=100, i=j=1; --trys>0 && (item[i][j]==OWALL || mitem[i][j]); i=rnd(MAXX-1), j=rnd(MAXY-1));
  1173. X                            if (trys) { mitem[i][j]=save[sc].id; hitp[i][j]=save[sc].arg; }
  1174. X                            }
  1175. X                        }
  1176. X                    loseint();
  1177. X                    draws(0,MAXX,0,MAXY);  if (wizard==0) spelknow[36]=0;
  1178. X                    free((char*)save);   positionplayer();  return;
  1179. X                    }
  1180. X
  1181. X        case 37:    /* permanence */ adjtime(-99999L);  spelknow[37]=0; /* forget */
  1182. X                    loseint();
  1183. X                    return;
  1184. X
  1185. X        default:    lprintf("  spell %d not available!",(long)x); beep();  return;
  1186. X        };
  1187. X    }
  1188. X
  1189. X/*
  1190. X    Create a guardian for a throne/altar/fountain, as a result of the player
  1191. X    using a VPR spell or pulverization scroll on it.
  1192. X*/
  1193. Xstatic void create_guardian( monst, x, y )
  1194. Xint monst;  /* monster code for the guardian */
  1195. Xint x, y;   /* coords of the object being guarded */
  1196. X    {
  1197. X    int k ;
  1198. X
  1199. X    /* prevent the guardian from being created on top of the player
  1200. X    */
  1201. X    if ((x == playerx) && (y == playery))
  1202. X    {
  1203. X    k = rnd(8);
  1204. X    x += diroffx[k];
  1205. X    y += diroffy[k];
  1206. X    }
  1207. X    know[x][y] = 0;
  1208. X    mitem[x][y] = monst ;
  1209. X    hitp[x][y]  = monster[monst].hitpoints;
  1210. X    }
  1211. X
  1212. X/*
  1213. X *  loseint()       Routine to subtract 1 from your int (intelligence) if > 3
  1214. X *
  1215. X *  No arguments and no return value
  1216. X */
  1217. Xstatic loseint()
  1218. X    {
  1219. X    if (--c[INTELLIGENCE]<3)  c[INTELLIGENCE]=3;
  1220. X    }
  1221. X
  1222. X/*
  1223. X *  isconfuse()         Routine to check to see if player is confused
  1224. X *
  1225. X *  This routine prints out a message saying "You can't aim your magic!"
  1226. X *  returns 0 if not confused, non-zero (time remaining confused) if confused
  1227. X */
  1228. Xstatic isconfuse()
  1229. X    {
  1230. X    if (c[CONFUSE]) { lprcat(" You can't aim your magic!"); beep(); }
  1231. X    return(c[CONFUSE]);
  1232. X    }
  1233. X
  1234. X/*
  1235. X *  nospell(x,monst)    Routine to return 1 if a spell doesn't affect a monster
  1236. X *      int x,monst;
  1237. X *
  1238. X *  Subroutine to return 1 if the spell can't affect the monster
  1239. X *    otherwise returns 0
  1240. X *  Enter with the spell number in x, and the monster number in monst.
  1241. X */
  1242. Xstatic nospell(x,monst)
  1243. X    int x,monst;
  1244. X    {
  1245. X    register int tmp;
  1246. X    if (x>=SPNUM || monst>=MAXMONST+8 || monst<0 || x<0) return(0); /* bad spell or monst */
  1247. X    if ((tmp=spelweird[monst-1][x])==0) return(0);
  1248. X    cursors();  lprc('\n');  lprintf(spelmes[tmp],monster[monst].name);  return(1);
  1249. X    }
  1250. X
  1251. X/*
  1252. X *  fullhit(xx)     Function to return full damage against a monster (aka web)
  1253. X *      int xx;
  1254. X *
  1255. X *  Function to return hp damage to monster due to a number of full hits
  1256. X *  Enter with the number of full hits being done
  1257. X */
  1258. Xfullhit(xx)
  1259. X    int xx;
  1260. X    {
  1261. X    register int i;
  1262. X    if (xx<0 || xx>20) return(0);   /* fullhits are out of range */
  1263. X    if (c[LANCEDEATH]) return(10000);   /* lance of death */
  1264. X    i = xx * ((c[WCLASS]>>1)+c[STRENGTH]+c[STREXTRA]-c[HARDGAME]-12+c[MOREDAM]);
  1265. X    return( (i>=1) ? i : xx );
  1266. X    }
  1267. X
  1268. X/*
  1269. X *  direct(spnum,dam,str,arg)   Routine to direct spell damage 1 square in 1 dir
  1270. X *      int spnum,dam,arg;
  1271. X *      char *str;
  1272. X *
  1273. X *  Routine to ask for a direction to a spell and then hit the monster
  1274. X *  Enter with the spell number in spnum, the damage to be done in dam,
  1275. X *    lprintf format string in str, and lprintf's argument in arg.
  1276. X *  Returns no value.
  1277. X */
  1278. Xstatic direct(spnum,dam,str,arg)
  1279. X    int spnum,dam,arg;
  1280. X    char *str;
  1281. X    {
  1282. X    extern char lastmonst[];
  1283. X    int x,y;
  1284. X    register int m;
  1285. X    if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad arguments */
  1286. X    if (isconfuse()) return;
  1287. X    dirsub(&x,&y);
  1288. X    m = mitem[x][y];
  1289. X    if (item[x][y]==OMIRROR)
  1290. X        {
  1291. X        if (spnum==3) /* sleep */
  1292. X            {
  1293. X            lprcat("You fall asleep! "); beep();
  1294. X        fool:
  1295. X            arg += 2;
  1296. X            while (arg-- > 0) { parse2(); nap(1000); }
  1297. X            return;
  1298. X            }
  1299. X        else if (spnum==6) /* web */
  1300. X            {
  1301. X            lprcat("You get stuck in your own web! "); beep();
  1302. X            goto fool;
  1303. X            }
  1304. X        else
  1305. X            {
  1306. X            lastnum=278; 
  1307. X            lprintf(str,"spell caster (thats you)",(long)arg);
  1308. X            beep(); losehp(dam); return;
  1309. X            }
  1310. X        }
  1311. X    if (m==0)
  1312. X        {   lprcat("  There wasn't anything there!");   return;  }
  1313. X    ifblind(x,y);
  1314. X    if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
  1315. X    lprintf(str,lastmonst,(long)arg);       hitm(x,y,dam);
  1316. X    }
  1317. X
  1318. X/*
  1319. X *  godirect(spnum,dam,str,delay,cshow)     Function to perform missile attacks
  1320. X *      int spnum,dam,delay;
  1321. X *      char *str,cshow;
  1322. X *
  1323. X *  Function to hit in a direction from a missile weapon and have it keep
  1324. X *  on going in that direction until its power is exhausted
  1325. X *  Enter with the spell number in spnum, the power of the weapon in hp,
  1326. X *    lprintf format string in str, the # of milliseconds to delay between 
  1327. X *    locations in delay, and the character to represent the weapon in cshow.
  1328. X *  Returns no value.
  1329. X */
  1330. Xgodirect(spnum,dam,str,delay,cshow)
  1331. X    int spnum,dam,delay;
  1332. X    char *str,cshow;
  1333. X    {
  1334. X    extern char lastmonst[] ;
  1335. X    register char *p;
  1336. X    register int x,y,m;
  1337. X    int dx,dy;
  1338. X    if (spnum<0 || spnum>=SPNUM || str==0 || delay<0) return; /* bad args */
  1339. X    if (isconfuse()) return;
  1340. X    dirsub(&dx,&dy);    x=dx;   y=dy;
  1341. X    dx = x-playerx;     dy = y-playery;     x = playerx;    y = playery;
  1342. X    while (dam>0)
  1343. X        {
  1344. X        x += dx;    y += dy;
  1345. X        if ((x > MAXX-1) || (y > MAXY-1) || (x < 0) || (y < 0))
  1346. X            {
  1347. X            dam=0;  break;  /* out of bounds */
  1348. X            }
  1349. X        if ((x==playerx) && (y==playery)) /* if energy hits player */
  1350. X            {
  1351. X            cursors(); lprcat("\nYou are hit my your own magic!"); beep();
  1352. X            lastnum=278;  losehp(dam);  return;
  1353. X            }
  1354. X        if (c[BLINDCOUNT]==0) /* if not blind show effect */
  1355. X            {
  1356. X            cursor(x+1,y+1); lprc(cshow); nap(delay); show1cell(x,y);
  1357. X            }
  1358. X        if ((m=mitem[x][y]))    /* is there a monster there? */
  1359. X            {
  1360. X            ifblind(x,y);
  1361. X            if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
  1362. X            cursors(); lprc('\n');
  1363. X            lprintf(str,lastmonst);     dam -= hitm(x,y,dam);
  1364. X            show1cell(x,y);  nap(1000);     x -= dx;    y -= dy;
  1365. X            }
  1366. X        else switch (*(p= &item[x][y]))
  1367. X            {
  1368. X        case OWALL:
  1369. X        cursors();
  1370. X        lprc('\n');
  1371. X        lprintf(str,"wall");
  1372. X        if (dam>=50+c[HARDGAME]) /* enough damage? */
  1373. X            if (level<MAXLEVEL+MAXVLEVEL-1) /* not on V3 */
  1374. X            if ((x<MAXX-1) && (y<MAXY-1) && (x) && (y))
  1375. X                            {
  1376. X                            lprcat("  The wall crumbles");
  1377. X                *p=0;
  1378. X                know[x][y]=0;
  1379. X                            show1cell(x,y);
  1380. X                            }
  1381. X        dam = 0;
  1382. X        break;
  1383. X
  1384. X        case OCLOSEDDOOR:
  1385. X        cursors();
  1386. X        lprc('\n');
  1387. X        lprintf(str,"door");
  1388. X        if (dam>=40)
  1389. X            {
  1390. X            lprcat("  The door is blasted apart");
  1391. X            *p = 0;
  1392. X            know[x][y] = 0;
  1393. X            show1cell( x, y );
  1394. X            }
  1395. X        dam = 0 ;
  1396. X        break;
  1397. X
  1398. X        case OSTATUE:
  1399. X        cursors();
  1400. X        lprc('\n');
  1401. X        lprintf(str,"statue");
  1402. X        if (c[HARDGAME]<3)
  1403. X            if (dam>44)
  1404. X            {
  1405. X            lprcat("  The statue crumbles");
  1406. X            *p=OBOOK;
  1407. X            iarg[x][y]=level;
  1408. X            know[x][y] = 0;
  1409. X            show1cell( x, y );
  1410. X            }
  1411. X        dam = 0 ;
  1412. X        break;
  1413. X
  1414. X        case OTHRONE:
  1415. X        cursors();
  1416. X        lprc('\n');
  1417. X        lprintf(str,"throne");
  1418. X        if (dam>39)
  1419. X            {
  1420. X            *p = OTHRONE2;
  1421. X            create_guardian( GNOMEKING, x, y );
  1422. X            show1cell( x, y );
  1423. X            }
  1424. X        dam = 0;
  1425. X        break;
  1426. X
  1427. X        case OALTAR:
  1428. X        cursors();
  1429. X        lprc('\n');
  1430. X        lprintf(str, "altar");
  1431. X        if ( dam > 75 - ( c[HARDGAME] >> 2 ))
  1432. X            {
  1433. X            create_guardian( DEMONPRINCE, x, y );
  1434. X            show1cell( x, y );
  1435. X            }
  1436. X        dam = 0 ;
  1437. X        break;
  1438. X
  1439. X        case OFOUNTAIN:
  1440. X        cursors();
  1441. X        lprc('\n');
  1442. X        lprintf(str, "fountain");
  1443. X        if ( dam > 55 )
  1444. X            {
  1445. X            create_guardian( WATERLORD, x, y );
  1446. X            show1cell( x, y );
  1447. X            }
  1448. X        dam = 0 ;
  1449. X        break;
  1450. X
  1451. X        case OMIRROR:
  1452. X    {
  1453. X    int bounce = FALSE, odx=dx, ody=dy ;
  1454. X        /* spells may bounce directly back or off at an angle
  1455. X        */
  1456. X        if (rnd(100) < 50 )
  1457. X        {
  1458. X        bounce = TRUE ;
  1459. X        dx *= -1;
  1460. X        }
  1461. X        if (rnd(100) < 50 )
  1462. X        {
  1463. X        bounce = TRUE ;
  1464. X        dy *= -1;
  1465. X        }
  1466. X    if (!bounce || ((odx==dx) && (ody==dy)))    /* guarentee a bounce */
  1467. X        {
  1468. X    dx = -odx;
  1469. X    dy = -ody;
  1470. X        }
  1471. X        }
  1472. X        break;
  1473. X            };
  1474. X        dam -= 3 + (c[HARDGAME]>>1);
  1475. X        }
  1476. X    }
  1477. X
  1478. X/*
  1479. X *  ifblind(x,y)    Routine to put "monster" or the monster name into lastmosnt
  1480. X *      int x,y;
  1481. X *
  1482. X *  Subroutine to copy the word "monster" into lastmonst if the player is blind
  1483. X *  Enter with the coordinates (x,y) of the monster
  1484. X *  Returns no value.
  1485. X */
  1486. Xifblind(x,y)
  1487. X    int x,y;
  1488. X    {
  1489. X    extern char lastmonst[] ;
  1490. X    char *p;
  1491. X    vxy(&x,&y); /* verify correct x,y coordinates */
  1492. X    if (c[BLINDCOUNT]) { lastnum=279;  p="monster"; }
  1493. X        else { lastnum=mitem[x][y];  p=monster[lastnum].name; }
  1494. X    strcpy(lastmonst,p);
  1495. X    }
  1496. X
  1497. X/*
  1498. X *  tdirect(spnum)      Routine to teleport away a monster
  1499. X *      int spnum;
  1500. X *
  1501. X *  Routine to ask for a direction to a spell and then teleport away monster
  1502. X *  Enter with the spell number that wants to teleport away
  1503. X *  Returns no value.
  1504. X */
  1505. Xstatic tdirect(spnum)
  1506. X    int spnum;
  1507. X    {
  1508. X    int x,y;
  1509. X    register int m;
  1510. X    if (spnum<0 || spnum>=SPNUM) return; /* bad args */
  1511. X    if (isconfuse()) return;
  1512. X    dirsub(&x,&y);
  1513. X    if ((m=mitem[x][y])==0)
  1514. X        {   lprcat("  There wasn't anything there!");   return;  }
  1515. X    ifblind(x,y);
  1516. X    if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
  1517. X    fillmonst(m);  mitem[x][y]=0; know[x][y] &= ~KNOWHERE;
  1518. X    }
  1519. X
  1520. X/*
  1521. X *  omnidirect(sp,dam,str)   Routine to damage all monsters 1 square from player
  1522. X *      int sp,dam;
  1523. X *      char *str;
  1524. X *
  1525. X *  Routine to cast a spell and then hit the monster in all directions
  1526. X *  Enter with the spell number in sp, the damage done to wach square in dam,
  1527. X *    and the lprintf string to identify the spell in str.
  1528. X *  Returns no value.
  1529. X */
  1530. Xstatic omnidirect(spnum,dam,str)
  1531. X    int spnum,dam;
  1532. X    char *str;
  1533. X    {
  1534. X    extern char lastmonst[] ;
  1535. X    register int x,y,m;
  1536. X    if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad args */
  1537. X    for (x=playerx-1; x<playerx+2; x++)
  1538. X        for (y=playery-1; y<playery+2; y++)
  1539. X            {
  1540. X            if (m=mitem[x][y])
  1541. X                if (nospell(spnum,m) == 0)
  1542. X                    {
  1543. X                    ifblind(x,y);
  1544. X                    cursors(); lprc('\n'); lprintf(str,lastmonst);
  1545. X                    hitm(x,y,dam);  nap(800);
  1546. X                    }
  1547. X                else  { lasthx=x;  lasthy=y; }
  1548. X            }
  1549. X    }
  1550. X
  1551. X/*
  1552. X *  dirsub(x,y)      Routine to ask for direction, then modify playerx,
  1553. X *                   playery for it
  1554. X *      int *x,*y;
  1555. X *
  1556. X *  Function to ask for a direction and modify an x,y for that direction
  1557. X *  Enter with the coordinate destination (x,y).
  1558. X *  Returns index into diroffx[] (0-8).
  1559. X */
  1560. Xdirsub(x,y)
  1561. X    int *x,*y;
  1562. X    {
  1563. X    register int i;
  1564. X    lprcat("\nIn What Direction? ");
  1565. X    for (i=0; ; )
  1566. X        switch(ttgetch())
  1567. X            {
  1568. X            case 'b':   i++;
  1569. X            case 'n':   i++;
  1570. X            case 'y':   i++;
  1571. X            case 'u':   i++;
  1572. X            case 'h':   i++;
  1573. X            case 'k':   i++;
  1574. X            case 'l':   i++;
  1575. X            case 'j':   i++;        goto out;
  1576. X            };
  1577. Xout:
  1578. X    *x = playerx+diroffx[i];        *y = playery+diroffy[i];
  1579. X    vxy(x,y);  return(i);
  1580. X    }
  1581. X
  1582. X/*
  1583. X *  dirpoly(spnum)      Routine to ask for a direction and polymorph a monst
  1584. X *      int spnum;
  1585. X *
  1586. X *  Subroutine to polymorph a monster and ask for the direction its in
  1587. X *  Enter with the spell number in spmun.
  1588. X *  Returns no value.
  1589. X */
  1590. Xstatic dirpoly(spnum)
  1591. X    int spnum;
  1592. X    {
  1593. X    int x,y,m;
  1594. X    if (spnum<0 || spnum>=SPNUM) return; /* bad args */
  1595. X    if (isconfuse()) return;    /* if he is confused, he can't aim his magic */
  1596. X    dirsub(&x,&y);
  1597. X    if (mitem[x][y]==0)
  1598. X        {   lprcat("  There wasn't anything there!");   return;  }
  1599. X    ifblind(x,y);
  1600. X    if (nospell(spnum,mitem[x][y])) { lasthx=x;  lasthy=y; return; }
  1601. X# ifdef MSDOS
  1602. X    do {
  1603. X        m = rnd(MAXMONST+7);
  1604. X        mitem[x][y] = m;
  1605. X    } while ( monster[m].genocided );
  1606. X# else
  1607. X    while ( monster[m = mitem[x][y] = rnd(MAXMONST+7)].genocided );
  1608. X# endif
  1609. X    hitp[x][y] = monster[m].hitpoints;
  1610. X    show1cell(x,y);  /* show the new monster */
  1611. X    }
  1612. X
  1613. X/*
  1614. X *  annihilate()    Routine to annihilate all monsters around player (playerx,playery)
  1615. X *
  1616. X *  Gives player experience, but no dropped objects
  1617. X *  Returns the experience gained from all monsters killed
  1618. X */
  1619. Xannihilate()
  1620. X    {
  1621. X    int i,j;
  1622. X    register long k;
  1623. X    register char *p;
  1624. X    for (k=0, i=playerx-1; i<=playerx+1; i++)
  1625. X      for (j=playery-1; j<=playery+1; j++)
  1626. X        if (!vxy(&i,&j)) /* if not out of bounds */
  1627. X            if (*(p= &mitem[i][j])) /* if a monster there */
  1628. X                if (*p<DEMONLORD+2)
  1629. X                    {
  1630. X# ifdef DGK
  1631. X                    k += monster[*p].experience;    *p=know[i][j] &= ~KNOWHERE;
  1632. X# else
  1633. X                    k += monster[*p].experience;    *p=know[i][j]=0;
  1634. X# endif
  1635. X                    }
  1636. X                else
  1637. X                    {
  1638. X                    lprintf("\nThe %s barely escapes being annihilated!",monster[*p].name);
  1639. X                    hitp[i][j] = (hitp[i][j]>>1) + 1; /* lose half hit points*/
  1640. X                    }
  1641. X    if (k>0)
  1642. X        {
  1643. X        lprcat("\nYou hear loud screams of agony!");    raiseexperience((long)k);
  1644. X        }
  1645. X    return(k);
  1646. X    }
  1647. X
  1648. X/*
  1649. X *  genmonst()      Function to ask for monster and genocide from game
  1650. X *
  1651. X *  This is done by setting a flag in the monster[] structure
  1652. X */
  1653. Xstatic genmonst()
  1654. X    {
  1655. X    register int i,j;
  1656. X    cursors();  lprcat("\nGenocide what monster? ");
  1657. X    for (i=0; (!isalpha(i)) && (i!=' '); i=ttgetch());
  1658. X    lprc(i);
  1659. X    for (j=0; j<MAXMONST; j++)  /* search for the monster type */
  1660. X        if (monstnamelist[j]==i)    /* have we found it? */
  1661. X            {
  1662. X            monster[j].genocided=1; /* genocided from game */
  1663. X            lprintf("  There will be no more %s's",monster[j].name);
  1664. X            /* now wipe out monsters on this level */
  1665. X            newcavelevel(level); draws(0,MAXX,0,MAXY); bot_linex();
  1666. X            return;
  1667. X            }
  1668. X    lprcat("  You sense failure!");
  1669. X    }
  1670. END_OF_FILE
  1671. if test 27476 -ne `wc -c <'spells.c'`; then
  1672.     echo shar: \"'spells.c'\" unpacked with wrong size!
  1673. fi
  1674. # end of 'spells.c'
  1675. fi
  1676. echo shar: End of archive 5 \(of 11\).
  1677. cp /dev/null ark5isdone
  1678. MISSING=""
  1679. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  1680.     if test ! -f ark${I}isdone ; then
  1681.     MISSING="${MISSING} ${I}"
  1682.     fi
  1683. done
  1684. if test "${MISSING}" = "" ; then
  1685.     echo You have unpacked all 11 archives.
  1686.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1687. else
  1688.     echo You still need to unpack the following archives:
  1689.     echo "        " ${MISSING}
  1690. fi
  1691. ##  End of shell archive.
  1692. exit 0
  1693.